package com.bc.web.controller.org;

import java.io.File;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

import com.alibaba.fastjson.JSONObject;
import com.bc.common.CommonEnum.Resp;
import com.bc.common.PayType;
import com.bc.common.message.BaseResp;
import com.bc.common.message.DFReq;
import com.bc.web.config.SystemConfig;
import com.bc.web.config.SystemEnum.FilePath;
import com.bc.web.config.SystemEnum.PayOrderItemStatus;
import com.bc.web.model.Merch;
import com.bc.web.model.Org;
import com.bc.web.model.OrgUser;
import com.bc.web.model.PayOrder;
import com.bc.web.model.PayOrderItem;
import com.fs.common.extend.FSController;
import com.fs.common.extend.FSSearchCondition;
import com.fs.common.util.FSDate;
import com.fs.common.util.FSExcel;
import com.fs.common.util.FSHttp;
import com.fs.common.util.FSIDGenerate;
import com.fs.common.util.FSJson;
import com.fs.common.util.FSLog;
import com.fs.common.util.FSMD5;
import com.fs.common.util.FSRegex;
import com.fs.common.util.FSString;
import com.fs.common.util.FSThreadPoolExecutor;
import com.jfinal.aop.Before;
import com.jfinal.aop.Clear;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.tx.Tx;
import com.jfinal.upload.UploadFile;

public class PayOrderContoller extends FSController{
	
	public void search() {
		OrgUser orgUser = (OrgUser) getSession().getAttribute("orgUser");
		FSSearchCondition sc = super.getSearchCondition();
		sc.put("orgCode", orgUser.getOrgCode());
		setPageResultToRequest("items", PayOrder.dao.search(sc));
		render("order/orgPayList.html");
	}
	
	public void searchItem() {
		String batchNo = getPara("batchNo");
		List<PayOrderItem> items = PayOrderItem.dao.selectByBatchNo(batchNo);
		PayOrder order = PayOrder.dao.selectByBatchNo(batchNo);
		setAttr("order", order);
		setAttr("items", items);
		render("order/orgPayItemList.html");
	}
	
	public void addPage() {
		render("order/orgPayAdd.html");
	}
	
	@Before(Tx.class)
	public void add() throws Exception {
		OrgUser orgUser = (OrgUser) getSession().getAttribute("orgUser");
		UploadFile upload = getFile();
		String payPassword = getPara("payPassword");
		String merchCode = getPara("merchCode");
		if(FSMD5.codeFor(payPassword).equalsIgnoreCase(orgUser.getPayPassword()) == false) {
			upload.getFile().delete();
			renderFail("支付密码不正确!");
		}else {
			List<String[]> data = FSExcel.readXlsx(upload.getFile());
			List<String> errorMsg  = batchPay(data,merchCode);
			upload.getFile().delete();
			if(errorMsg.isEmpty()){
				renderSuccess();
			}else{
				StringBuffer sb = new StringBuffer();
				for (String msg : errorMsg) {
					sb.append(msg + "</br>");
				}
				renderFail(sb.toString());
			}
		}
	}
	
	public void merchLookup() {
		OrgUser orgUser = (OrgUser) getSession().getAttribute("orgUser");
		FSSearchCondition sc = super.getSearchCondition();
		sc.put("orgCode", orgUser.getOrgCode());
		Page<Merch> items = Merch.dao.search(sc);
		setPageResultToRequest("items", items);
		render("merch/merchLookup.html");
	}
	
	public void download(){
		renderFile(new File(FilePath.ReportTemplate.getValue() + "商户代付模版.xlsx"));
	}
	
	@Before(Tx.class)
	public void confirm() {
		String batchNo = getPara("batchNo");
		PayOrder order = PayOrder.dao.selectByBatchNo(batchNo);
		order.setIsConfirm(true);
		order.update();
		List<PayOrderItem> items = PayOrderItem.dao.selectByBatchNo(batchNo);
		send(items);
		renderSuccess("已提交申请,实际交易结果需要等待");
	}
	
	@Before(Tx.class)
	public void remove() {
		String batchNo = getPara("batchNo");
		PayOrder order = PayOrder.dao.selectByBatchNo(batchNo);
		order.delete();
		PayOrderItem.dao.deleteByBatchNo(batchNo);
		renderSuccess(false);
	}
	
	@Clear
	public void payNotify(){
		String notifyString = getStringFromRequest();
		FSLog.web.info("---------代付回调----------\r\n" + notifyString);
		JSONObject notifyResp = JSONObject.parseObject(notifyString);
		String respCode = notifyResp.getString("respCode");
		String merchCode = notifyResp.getString("merchCode");
		String merchOrderNo = notifyResp.getString("merchOrderNo");
		PayOrderItem orderItem = PayOrderItem.dao.selectByMerchOrderNo(merchCode, merchOrderNo);
		if(orderItem.getOrderStatus().equals(PayOrderItemStatus.InProcess.getValue())) {
			if(Resp.Success.getCode().equals(respCode)){
				orderItem.setOrderStatus(PayOrderItemStatus.TradeSuccess.getValue());
			}else if(("01").equals(respCode) || ("11").equals(respCode)){
				orderItem.setOrderStatus(PayOrderItemStatus.TradeFail.getValue());
			}
			orderItem.setRespCode(respCode);
			orderItem.setRespMsg(notifyResp.getString("respMsg"));
			orderItem.setTradeDateTime(FSDate.getDateTime());
			orderItem.update();
		}
		renderText("SUCCESS");
	}
	
	private List<String> batchPay(List<String[]> data,String merchCode){
		List<String> errorMsg = new ArrayList<>();
		Long amount;
		String accountName;
		String accountNo;
		String accountType;
		String bankName;
		String remark;
		String createDateTime = FSDate.getDateTime();
		List<PayOrderItem> saveList = new ArrayList<>();
		Merch merch = Merch.dao.selectByMerchCode(merchCode);
		String excelAmount;
		DecimalFormat df = new DecimalFormat("0.00");
		//生成统计单
		PayOrder order = new PayOrder();
		order.setBatchNo(getBatchNo());
		order.setTotalAmount(0L);
		order.setMerchCode(merchCode);
		order.setOrgCode(merch.getOrgCode());
		order.setIsConfirm(false);
		order.setCreateDateTime(FSDate.getDateTime());
		//第一行是标题
		String[] rowData;
		for (int i = 3; i < data.size(); i++) {
			rowData = data.get(i);
			if(StrKit.notBlank(rowData[0]) && getDecimalLength(rowData[0]) > 2) {
				errorMsg.add(i + 1 + "行:金额格式校验不通过,请确保小数点不能大于2位");
				continue;
			}
			
			excelAmount = df.format(new Double(rowData[0]));
			amount = new BigDecimal(excelAmount).multiply(new BigDecimal(100)).longValue();
			accountName = rowData[1].trim();
			accountNo = rowData[2].trim();
			bankName = rowData[3].trim();
			accountType = rowData[4].trim();
			remark = rowData[8].trim();
			
			if(StrKit.isBlank(accountName)) {
				errorMsg.add(i + 1 + "行:户名非空校验不通过");
				continue;
			}
			
			if(FSRegex.isPositiveInt(accountNo) == false){
				errorMsg.add(i + 1 + "行:行银行卡号校验不通过");
				continue;
			}
			
			if(StrKit.isBlank(accountType)) {
				errorMsg.add(i + 1 + "行:收款方类型校验不通过");
				continue;
			}
			
			if(StrKit.isBlank(remark)) {
				errorMsg.add(i + 1 + "行:备注不能为空");
				continue;
			}
			
			PayOrderItem item = new PayOrderItem();
			item.setId(FSIDGenerate.getUUID());
			item.setOrgCode(merch.getOrgCode());
			item.setMerchCode(merchCode);
			item.setMerchOrderNo(FSIDGenerate.getDateOrderNo());
			item.setAmount(Long.valueOf(amount));
			item.setAccountName(accountName);
			item.setAccountNumber(accountNo);
			item.setBatchNo(order.getBatchNo());
			item.setOrderStatus(PayOrderItemStatus.Create.getValue());
			item.setCreateDateTime(createDateTime);
			item.setBankName(bankName);
			item.setRemark(remark);
			
			if("企业".equals(accountType)) {
				if(StrKit.isBlank(rowData[5])) {
					errorMsg.add(i + 1 + "行:[开户行省份]非空校验不通过");
					continue;
				}
				if(StrKit.isBlank(rowData[6])) {
					errorMsg.add(i + 1 + "行:[开户行城市]非空校验不通过");
					continue;
				}
				if(StrKit.isBlank(rowData[7])) {
					errorMsg.add(i + 1 + "行:[开户行支行行名]非空校验不通过");
					continue;
				}
				item.setIsCompany(true);
				item.setProvince(rowData[5]);
				item.setCity(rowData[6]);
				item.setBranchName(rowData[7]);
			} else {
				if(StrKit.isBlank(rowData[5])) {
					errorMsg.add(i + 1 + "行:[开户行省份]非空校验不通过");
					continue;
				}
				if(StrKit.isBlank(rowData[6])) {
					errorMsg.add(i + 1 + "行:[开户行城市]非空校验不通过");
					continue;
				}
				if(StrKit.isBlank(rowData[7])) {
					errorMsg.add(i + 1 + "行:[开户行支行行名]非空校验不通过");
					continue;
				}
				item.setIsCompany(true);
				item.setProvince(rowData[5]);
				item.setCity(rowData[6]);
				item.setBranchName(rowData[7]);
				item.setIsCompany(false);
			}
			
			saveList.add(item);
			order.setTotalAmount(order.getTotalAmount().longValue() + item.getAmount().longValue());
		}
		
		if(errorMsg.isEmpty()) {
			String checkMsg = check(data.get(1), order.getTotalAmount(), saveList.size());
			if(StrKit.notBlank(checkMsg)) {
				errorMsg.add(checkMsg);
			}else {
				order.setTotalNumber(saveList.size());
				order.save();
				Db.batchSave(saveList, 100);
			}
		}
		return errorMsg;
	}
	
	private void send(List<PayOrderItem> items) {
		FSThreadPoolExecutor.execute(new Runnable() {
			
			@Override
			public void run() {
				for (PayOrderItem item : items) {
					final String localDomain = SystemConfig.config.get("local_domain");
					Org	org = Org.dao.selectByOrgCode(item.getOrgCode());
					DFReq req = new DFReq();
					req.setVersion("V.10");
					req.setOrgCode(item.getOrgCode());
					req.setMerchCode(item.getMerchCode());
					req.setMerchOrderNo(item.getMerchOrderNo());
					req.setAmount(String.valueOf(item.getAmount()));
					req.setAccountName(item.getAccountName());
					req.setAccountCardNo(item.getAccountNumber());
					req.setBankName(item.getBankName());
					if(item.getIsCompany()){
						req.setBranchName(item.getBranchName());
						req.setProvince(item.getProvince());
						req.setCity(item.getCity());
						req.setPayType(PayType.DF_COMPANY);
					}else{
						req.setBranchName(item.getBranchName());
						req.setProvince(item.getProvince());
						req.setCity(item.getCity());
						req.setPayType(PayType.DF_PERSONAL);
					}
					req.setNotifyUrl(localDomain + "/org/payorder/payNotify");
					req.setRemark(item.getRemark());
					req.setSign(FSMD5.sortSign(req, org.getSafeKey()));
					try {
						String tradeSystemUrl = SystemConfig.config.get("trade_system_url") + "/route";
						String result = FSHttp.postJson(tradeSystemUrl, FSJson.toString(req));
						FSLog.web.info("代付交易返回 ------>" + result);
						BaseResp rsp = JSONObject.parseObject(result, BaseResp.class);
						item.setRespCode(rsp.getRespCode());
						item.setRespMsg(rsp.getRespMsg());
						if(item.getRespCode().equals(Resp.Fail.getCode())){
							item.setOrderStatus(PayOrderItemStatus.TradeFail.getValue());
						}else {
							item.setOrderStatus(PayOrderItemStatus.InProcess.getValue());
						}
						item.update();
						FSLog.web.info("线程池执行代付操作结果 -> \r\n" + result);
					} catch (Exception e) {
						item.setOrderStatus(PayOrderItemStatus.InProcess.getValue());
						FSLog.web.error("线程池执行代付操作结果 -> 异常, 订单号=" + item.getMerchOrderNo(),e);
					} finally {
						item.update();
					}
				}
			}
			
		});
	}
	
	/**
	 * 获取小数点后长度
	 * @param src
	 * @return
	 */
	private int getDecimalLength(String src) {
		src = src.substring(src.lastIndexOf(".")+1);
		return src.length();
	}
	
	private String getBatchNo(){
		String batchNo = Db.queryFirst("select nextval('batchNo')").toString();
		batchNo = FSString.appendZeroToLeft(batchNo, 4);
		batchNo = "P" + FSDate.getDateNumber() + FSIDGenerate.getIntRandomCode(6) + batchNo;
		return batchNo;
	}
	
	private String check(String[] rowData,Long totalAmount,Integer total) {
		String res = "";
		Long excelTotalAmount = new BigDecimal(rowData[0]).multiply(new BigDecimal(100)).longValue();
		Integer excelTotal = Double.valueOf(rowData[1]).intValue();
		if(excelTotalAmount.longValue() != totalAmount.longValue()) {
			res += "[批总金额]与系统统计不符合";
		}
		if(excelTotal.intValue() != total.intValue()) {
			res += "\t[批总笔数]与系统统计不符合";
		}
		return res;
	}

}
